import os
import sys
import json
import logging
from typing import Dict, Any, Optional

# 添加项目根目录到Python路径
sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), '../../')))

from src.llm.llm__client import create_llm_client

# 配置日志
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s')
logger = logging.getLogger(__name__)

class ToolFramework:
    def __init__(self, config_path: str = None):
        """
        初始化工具框架
        
        Args:
            config_path: 配置文件路径，如果为None则使用默认路径
        """
        # 设置默认配置文件路径
        if config_path is None:
            current_dir = os.path.dirname(os.path.abspath(__file__))
            config_path = os.path.join(current_dir, 'config.json')
        
        self.config_path = config_path
        self.config = None
        self.llm_client = None
        
        # 加载配置
        self.load_config()
        
    def load_config(self):
        """
        加载配置文件
        
        Returns:
            dict: 配置信息
        """
        try:
            with open(self.config_path, 'r', encoding='utf-8') as f:
                self.config = json.load(f)
            logger.info(f"成功加载配置文件: {self.config_path}")
            return self.config
        except FileNotFoundError:
            logger.error(f"配置文件不存在: {self.config_path}")
            raise
        except json.JSONDecodeError as e:
            logger.error(f"配置文件格式错误: {e}")
            raise
        except Exception as e:
            logger.error(f"加载配置文件失败: {e}")
            raise
    
    def get_root_config(self, root_name: str) -> Optional[Dict[str, Any]]:
        """
        获取指定名称的根节点配置
        
        Args:
            root_name: 根节点名称
            
        Returns:
            dict or None: 根节点配置信息
        """
        if not self.config or 'root' not in self.config:
            logger.error("配置未加载或格式不正确")
            return None
        
        for root in self.config['root']:
            if root.get('name') == root_name:
                return root
        
        logger.warning(f"未找到根节点配置: {root_name}")
        return None
    
    def get_tools_by_names(self, tool_names: list) -> list:
        """
        根据工具名称列表获取工具配置
        
        Args:
            tool_names: 工具名称列表
            
        Returns:
            list: 工具配置列表
        """
        if not self.config or 'tools' not in self.config:
            logger.error("配置未加载或格式不正确")
            return []
        
        tools = []
        for tool_name in tool_names:
            for tool in self.config['tools']:
                if tool.get('name') == tool_name:
                    tools.append(tool)
                    break
            else:
                logger.warning(f"未找到工具配置: {tool_name}")
        
        return tools
    
    def get_template_path(self, template_name: str) -> str:
        """
        获取模板文件路径
        
        Args:
            template_name: 模板名称（不含扩展名）
            
        Returns:
            str: 模板文件完整路径
        """
        current_dir = os.path.dirname(os.path.abspath(__file__))
        template_mapping = {
            'requirement': 'require_temp.txt',
            'design': 'design_temp.txt',
            'testcases': 'test_temp.txt'
        }
        
        template_file = template_mapping.get(template_name, f'{template_name}_temp.txt')
        template_path = os.path.join(current_dir, 'template', template_file)
        
        return template_path
    
    def load_template(self, template_name: str) -> Optional[str]:
        """
        加载模板文件内容
        
        Args:
            template_name: 模板名称
            
        Returns:
            str or None: 模板内容
        """
        template_path = self.get_template_path(template_name)
        
        try:
            with open(template_path, 'r', encoding='utf-8') as f:
                content = f.read()
            logger.info(f"成功加载模板: {template_name}")
            return content
        except FileNotFoundError:
            logger.warning(f"模板文件不存在: {template_path}")
            return None
        except Exception as e:
            logger.error(f"加载模板失败: {e}")
            return None
    
    def process_with_llm(self, root_name: str, user_input: str, model_config: dict = None) -> Dict[str, Any]:
        """
        处理用户输入，调用大模型并执行工具回调
        
        Args:
            root_name: 配置文件根节点名字
            user_input: 用户输入的信息
            model_config: 模型配置参数
            
        Returns:
            dict: 处理结果
        """
        try:
            # 获取根节点配置
            root_config = self.get_root_config(root_name)
            if not root_config:
                return {
                    "status": "error",
                    "error_message": f"未找到根节点配置: {root_name}"
                }
            
            # 获取工具配置
            tool_names = root_config.get('tools', [])
            tools = self.get_tools_by_names(tool_names)
            
            # 获取系统提示
            system_prompt = root_config.get('system_prompt', '')
            template_path = root_config.get('system_template', '')
            
            # 读取模板文件内容
            template_content = ''
            if template_path:
                try:
                    # 构建完整的模板文件路径
                    current_dir = os.path.dirname(os.path.abspath(__file__))
                    full_template_path = os.path.join(current_dir, template_path)
                    
                    with open(full_template_path, 'r', encoding='utf-8') as f:
                        template_content = f.read()
                    logger.info(f"成功读取模板文件: {full_template_path}")
                except Exception as e:
                    logger.warning(f"读取模板文件失败: {e}，将使用空模板")
            
            # 组合完整的系统提示
            full_system_prompt = f"{system_prompt}\n\n{template_content}"
            
            logger.info(f"准备调用大模型，根节点: {root_name}，工具数量: {len(tools)}")
            
            # 初始化LLM客户端
            self.initialize_llm_client(model_config)
            
            # 调用大模型
            result = self.llm_client.call_with_tools(
                tools=tools,
                user_input=user_input,
                system_prompt=full_system_prompt
            )
            
            # 处理工具调用结果
            if result.get('status') == 'success' and 'tool_call' in result:
                tool_call = result['tool_call']
                tool_name = tool_call.get('name')
                tool_params = tool_call.get('parameters', {})
                
                logger.info(f"执行工具调用: {tool_name}")
                
                # 动态导入并执行对应的工具函数
                try:
                    # 根据工具名称确定模块路径
                    if 'requirement' in tool_name:
                        from src.tools.implment.doc.require_tool import save_requirement_file
                        tool_result = save_requirement_file(**tool_params)
                    elif 'design' in tool_name:
                        from src.tools.implment.doc.design_tool import save_design_file
                        tool_result = save_design_file(**tool_params)
                    elif 'testcases_file' in tool_name:
                        from src.tools.implment.doc.testcases_tools import save_testcases_file
                        tool_result = save_testcases_file(**tool_params)
                    elif 'save_code_file' == tool_name:
                        from src.tools.implment.code.codes_tool import save_code_file
                        tool_result = save_code_file(**tool_params)
                    elif 'save_test_code_file' == tool_name:
                        from src.tools.implment.code.testcases_tool import save_test_code_file
                        tool_result = save_test_code_file(**tool_params)
                    elif 'generate_codes_from_tasks' == tool_name:
                        from src.tools.implment.code.codes_tool import generate_codes_from_tasks
                        tool_result = generate_codes_from_tasks(**tool_params)
                    elif 'generate_test_codes_from_tasks' == tool_name:
                        from src.tools.implment.code.testcases_tool import generate_test_codes_from_tasks
                        tool_result = generate_test_codes_from_tasks(**tool_params)
                    else:
                        logger.warning(f"未实现的工具: {tool_name}")
                        tool_result = {"status": "error", "message": f"未实现的工具: {tool_name}"}
                    
                    logger.info(f"工具执行结果: {tool_result}")
                    result['tool_execution_result'] = tool_result
                    
                except Exception as e:
                    logger.error(f"执行工具时出错: {e}")
                    result['tool_execution_error'] = str(e)
            
            return result
            
        except Exception as e:
            logger.error(f"处理请求失败: {e}")
            import traceback
            logger.error(f"异常堆栈: {traceback.format_exc()}")
            return {
                "status": "error",
                "error_message": str(e),
                "exception": traceback.format_exc()
            }
    
    def initialize_llm_client(self, model_config: dict = None):
        """
        初始化LLM客户端
        
        Args:
            model_config: 模型配置参数
        """
        self.llm_client = create_llm_client(model_config)
        logger.info("LLM客户端已初始化")
    
    def close(self):
        """
        关闭框架资源
        """
        if self.llm_client:
            try:
                self.llm_client.close()
                logger.info("框架资源已关闭")
            except Exception as e:
                logger.error(f"关闭资源时出错: {e}")

# 便捷函数
def process_root_request(root_name: str, user_input: str, config_path: str = None, model_config: dict = None) -> Dict[str, Any]:
    """
    处理根节点请求的便捷函数
    
    Args:
        root_name: 配置文件根节点名字
        user_input: 用户输入的信息
        config_path: 配置文件路径
        model_config: 模型配置参数
        
    Returns:
        dict: 处理结果
    """
    framework = ToolFramework(config_path)
    try:
        return framework.process_with_llm(root_name, user_input, model_config)
    finally:
        framework.close()

# 示例用法
if __name__ == "__main__":
    # 示例1: 使用需求文档根节点
    result1 = process_root_request(
        root_name="requirement_document",
        user_input="创建一个在线购物系统的需求文档，主要功能包括用户注册登录、商品浏览、购物车、下单支付等。"
    )
    print("\n需求文档处理结果:")
    print(json.dumps(result1, ensure_ascii=False, indent=2))
    
    # 示例2: 使用设计文档根节点
    result2 = process_root_request(
        root_name="design_document",
        user_input="为在线购物系统设计一个基于React+Django的架构方案。"
    )
    print("\n设计文档处理结果:")
    print(json.dumps(result2, ensure_ascii=False, indent=2))
    
    # 示例3: 使用测试用例文档根节点
    result3 = process_root_request(
        root_name="testcases_document",
        user_input="为在线购物系统的用户登录功能编写测试用例。"
    )
    print("\n测试用例文档处理结果:")
    print(json.dumps(result3, ensure_ascii=False, indent=2))